package net.sf.rose.jdbc.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import net.sf.rose.jdbc.PageBean;
import net.sf.rose.jdbc.query.QuerySQL;
import net.sf.rose.jdbc.query.SimpleSQL;
import net.sf.rose.jdbc.service.Service;
import net.sf.rose.util.BeanWrapper;
import net.sf.rose.util.ClassUtils;
import net.sf.rose.util.RoseRuntimeException;

/**
 * 类说明：简单的数据库操作的封装类
 * 
 * @author fengjian
 * @since 2013/05/18
 */
@SuppressWarnings("unchecked")
public class SimpleDAO extends GenericDAO {

	private static Logger LOG = Logger.getLogger(SimpleDAO.class);

	public SimpleDAO() {
		super();
		super.setService(Service.getService());
	}

	public SimpleDAO(Service service) {
		super();
		this.setService(service);
	}

	/**
	 * 功能:返回数据库操作SQL语句生成实例
	 * 
	 * @return 数据库操作SQL语句生成实例
	 */
	@Override
	public SimpleSQL getQuerySQL() {
		if (super.query == null) {
			query = new SimpleSQL();
			query.setService(service);
			super.query = query;
		}
		return (SimpleSQL) super.query;
	}

	/**
	 * 功能:从数据库中读取指定的数据类
	 * <p>
	 * 如果查询没有结果，则抛出异常
	 * <p>
	 * 如果查询有多个结果，则抛出异常
	 * 
	 * @param <T> - 返回的Map数据类型
	 * @return 返回取得的数据类
	 */
	@Override
	public <T> T load() {
		try {
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.con = service.getConnection();
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			Object obj = toMap(rs);
			if (obj == null) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法未能找到结果记录！\n" + logString);
			}
			if (rs.next()) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法能找到结果记录不止一条！\n" + logString);
			}
			return (T) obj;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库load查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:从数据库中读取某个值
	 * <p>
	 * 如果查询没有结果，则抛出异常
	 * <p>
	 * 如果查询有多个结果，则抛出异常
	 * 
	 * @param <T> 返回的某个值
	 * @return 返回取得的某个值
	 */
	public <T> T getValue() {
		try {
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.con = service.getConnection();
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			if (!rs.next()) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法未能找到结果记录！\n" + logString);
			}
			Object obj = rs.getObject(1);
			if (rs.next()) {
				throw new RoseRuntimeException("根据指定的sql语句调用load方法能找到结果记录不止一条！\n" + logString);
			}
			return (T) obj;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库getValue查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:从数据库中读取指定的数据类
	 * <p>
	 * 如果查询没有结果，则返回null
	 * <p>
	 * 如果查询有多个结果，则返回第一条记录
	 * 
	 * @param <T> - 返回的Map数据类型
	 * @return 返回取得的数据类
	 */
	@Override
	public <T> T get() {
		try {
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.con = service.getConnection();
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			Object map = toMap(rs);
			return map == null ? null : (T) map;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库get查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:通过SQL取得数据类列表
	 * 
	 * @param <T> - 返回的Map数据类型
	 * @return 返回取得的数据列表
	 */
	@Override
	public <T> List<T> list() {
		// 执行SQL语句
		try {
			this.con = service.getConnection();
			// 如果排序有内容，把排序加上
			if (query.getOrderBy().size() > 0) {
				StringBuilder sb = new StringBuilder();
				sb.append(" ORDER BY ");
				for (String[] arr : query.getOrderBy()) {
					sb.append(arr[0]);
					if (arr[1] != null) {
						sb.append(' ').append(arr[1]).append(',');
					} else {
						sb.append(',');
					}
				}
				query.addSql(sb.substring(0, sb.length() - 1));
			}
			// 如果需要分页
			if (query.getPage() != null) {
				PageBean page = query.getPage();
				// 如果不是oracle
				if (!service.getDatabaseType().equals("oracle")) {
					this.fillStatement(query.getCountSql(), query.getParameterList());
					rs = pstmt.executeQuery();
					if (rs.next()) {
						long count = rs.getLong(1);
						if (count != 0) {
							// 保存符合条件的记录数量
							page.setTotal(Integer.parseInt(count + ""));
						}
					}
				}
			}
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			List<Object> list = toMapList(rs, query);
			// 清空分页组件
			query.setPage(null);
			return (List<T>) list;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库list查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:通过SQL取得数据类列表
	 * 
	 * @return 数据数组
	 */
	public Object[][] array() {
		// 执行SQL语句
		try {
			this.con = service.getConnection();
			// 如果排序有内容，把排序加上
			if (query.getOrderBy().size() > 0) {
				StringBuilder sb = new StringBuilder();
				sb.append(" ORDER BY ");
				for (String[] arr : query.getOrderBy()) {
					sb.append(arr[0]);
					if (arr[1] != null) {
						sb.append(' ').append(arr[1]).append(',');
					} else {
						sb.append(',');
					}
				}
				query.addSql(sb.substring(0, sb.length() - 1));
			}
			// 如果需要分页
			if (query.getPage() != null) {
				PageBean page = query.getPage();
				this.fillStatement(query.getCountSql(), query.getParameterList());
				rs = pstmt.executeQuery();
				if (rs.next()) {
					long count = rs.getLong(1);
					if (count != 0) {
						// 保存符合条件的记录数量
						page.setTotal(Integer.parseInt(count + ""));
					}
				}
			}
			if (super.isRecordLog()) {
				// 拼写SQL语句日志
				logString = query.getLog().trim();
				LOG.info(logString);
			}
			this.fillStatement(query.getSql(), query.getParameterList());
			rs = pstmt.executeQuery();
			Object[][] list = toDataArray(rs, query);
			// 清空分页组件
			query.setPage(null);
			return list;
		} catch (SQLException e) {
			throw ClassUtils.getException("数据库array查询操作失败！sql:" + getLogString(logString), e);
		} catch (Exception e) {
			throw ClassUtils.getException("数据库操作发生未知异常！", e);
		} finally {
			closeResult();
		}
	}

	/**
	 * 功能:将数据库查询结果集中的数据列表加载入DataBean类，并封装至ArrayList类中。
	 * 
	 * @param rs    - ResultSet结果集
	 * @param query - 自动拼接SQL语句类
	 * @return List<DataBean>数据列表
	 * @throws SQLException
	 */
	private List<Object> toMapList(ResultSet rs, QuerySQL query) throws Exception {
		if (!rs.next()) {
			return new java.util.ArrayList<Object>();
		}
		String[] colnames = getColNames(rs);
		int columnCount = colnames.length;
		PageBean page = query.getPage();
		Object val = null;
		rs.last(); // 移到最后一行
		int size = rs.getRow(); // 得到当前行号，也就是记录数
		rs.beforeFirst(); // 把指针再移到初始化的位置
		Map<String, Object> data = null;
		List<Object> list = new java.util.ArrayList<>(size);
		Class<?> entityClass = query.getEntityClass();
		if (entityClass != null) {
			Object t;
			BeanWrapper bw = new BeanWrapper();
			while (rs.next()) {
				t = entityClass.newInstance();
				bw.setWrappedInstance(t);
				for (int i = 1; i <= columnCount; i++) {
					val = null;
					val = rs.getObject(i);
					if (val != null) {
						bw.set(colnames[i - 1], val);
					}
				}
				list.add(t);
			}
		} else {
			while (rs.next()) {
				if (returnDataType == RETURN_DATA_TYPE_HASHMAP) {
					data = new HashMap<>();
				} else {
					data = new LinkedHashMap<>();
				}
				for (int i = 1; i <= columnCount; i++) {
					val = rs.getObject(i);
					if (val != null)
						data.put(colnames[i - 1], val);
				}
				list.add(data);
			}
		}
		// 如果需要分页，将结果数据集装入分页类中
		if (page != null) {
			page.setData(list);
		}
		return list;
	}

	/**
	 * 功能:将数据库查询结果集中的数据加载入DataBean类中。
	 * 
	 * @param rs - ResultSet结果集
	 * @return DataBean数据类
	 * @throws SQLException
	 */
	private Object toMap(ResultSet rs) throws Exception {
		if (!rs.next()) {
			return null;
		}
		Object val = null;
		String[] colnames = getColNames(rs);
		int columnCount = colnames.length;

		Class<?> entityClass = query.getEntityClass();
		if (entityClass != null) {
			Object t = entityClass.newInstance();
			BeanWrapper bw = new BeanWrapper();
			bw.setWrappedInstance(t);
			for (int i = 1; i <= columnCount; i++) {
				val = null;
				val = rs.getObject(i);
				if (val != null) {
					bw.set(colnames[i - 1], val);
				}
			}
			return t;
		} else {
			Map<String, Object> data = null;
			if (returnDataType == RETURN_DATA_TYPE_HASHMAP) {
				data = new HashMap<>();
			} else {
				data = new LinkedHashMap<>();
			}
			for (String key : colnames) {
				val = rs.getObject(key);
				if (val != null) {
					data.put(key, val);
				}
			}
			return data;
		}
	}

	/**
	 * 功能:将数据库查询结果集中的数据列表加载入DataBean类，并封装至ArrayList类中。
	 * 
	 * @param rs    - ResultSet结果集
	 * @param query - 自动拼接SQL语句类
	 * @return List<DataBean>数据列表
	 * @throws SQLException
	 */
	private Object[][] toDataArray(ResultSet rs, QuerySQL query) throws SQLException {
		if (!rs.next()) {
			return new Object[0][];
		}
		String[] colnames = getColNames(rs);
		int columnCount = colnames.length;
		PageBean page = query.getPage();
		rs.last(); // 移到最后一行
		int size = rs.getRow(); // 得到当前行号，也就是记录数
		rs.beforeFirst(); // 把指针再移到初始化的位置
		Object[][] list = new Object[size][columnCount];
		int index = 0;
		while (rs.next()) {
			Object[] data = new Object[columnCount];
			for (int i = 1; i <= columnCount; i++) {
				data[i - 1] = rs.getObject(i);
			}
			list[index++] = data;
		}
		// 如果需要分页，将结果数据集装入分页类中
		if (page != null) {
			page.setData(list);
		}
		return list;
	}

}
